<?php /* 
==================================================
TextCMS -- simple plain/text CMS with GPL licence
CAPTCHA module
(c) 2008, 4X_Pro
Visit us online: http://textcms.ru
==================================================
*/

// Раскомментиуйте следующую строку, чтобы использовать более быстрый режим проверки CAPCTCHA, в случае, если вы используете защиту файла files/captcha2.txt средствами сервера (т.е. клиент не имеет возможности его просмотреть)
// define('CAPTCHA_SECURE_FILE','1'); 

/** Замена конструкций <!-- CAPTCHA_descr --> и <!-- CAPTCHA_img --> 
на описание и картинку CAPTCHA **/  
function captcha_set_elements($page,$reload=false) {
	if (preg_match('/<!--\s*CAPTCHA_img\s*-->/s',$page)) {
		$code = md5(mt_rand());
		if (!defined('CAPTCHA_SECURE_FILE')) {
			$filename='files/captcha1.txt';
			$fh=fopen($filename,'a');
			if (!$fh) trigger_error('Файл files/captcha1.txt не доступен для записи!',E_USER_ERROR);
			flock($fh,LOCK_EX);
			fputs($fh,':'.$code.":\n");
			fclose($fh);
		}
		if (!$reload || (!isset($_REQUEST['captcha_text']) && !isset($_REQUEST['captcha_code']))) {
  		$page=preg_replace('/<!--\s*CAPTCHA_img\s*-->/s','<input type="text" size="8" name="captcha_text" /><input type="hidden" name="captcha_code" value="'.$code.'" /> <img src="'.$GLOBALS['sitepath'].'captcha.php?code='.$code.'" alt="Включите графику, чтобы увидеть защитный код" />',$page);
	  	$page=preg_replace('/<!--\s*CAPTCHA_descr\s*-->/s','Введите защитный код, показанный на картинке:',$page);
		}
		else {
  		$page=preg_replace('/<!--\s*CAPTCHA_img\s*-->/s','<input type="hidden" name="captcha_text" value="'.htmlspecialchars($_REQUEST['captcha_text']).'"/><input type="hidden" name="captcha_code" value="'.htmlspecialchars($_REQUEST['captcha_code']).'" />',$page);
	  	$page=preg_replace('/<!--\s*CAPTCHA_descr\s*-->/s','',$page);			
		}
	}
	return $page;
}

/** Проверка корректности введенного пользователем кода **/
function captcha_check($clean=true) {
	if	(!isset($_REQUEST['captcha_text']) || !$_REQUEST['captcha_text']
	|| !isset($_REQUEST['captcha_code']) || !$_REQUEST['captcha_code']) return false; // если строка или код CAPTCHA пусты, считаем проверку провалившейся сразу, чтобы не тратить время на чтение файла
	
	$filename='files/captcha2.txt';
  if (!file_exists($filename)) return false;	
  $data=file($filename);
	if (!is_array($data) || count($data)==0) return false; // если не удалось прочитать файл или код CAPTCHA пуст, считаем проверку провалившейся сразу
	$oldtime=time()-3*60*60; // будем считать, что CAPTCHA устаревает через 3 часа
	$result=false;
	$buffer='';
	if (count($data)>10000) $data=array_slice(10000); // если кодов набралось слишком много, просматриваем и сохраняем последние 10000 (защита от DDoS-атаки) 
	for ($i=0, $count=count($data); $i<$count; $i++) {
		list($code,$time,$hash)=explode(':',$data[$i]);
		if ($code==$_REQUEST['captcha_code']) {
			if (md5('4X_ProCaptcha'.$_REQUEST['captcha_code'].$_REQUEST['captcha_text'])."\n"==$hash) $result=true;
			if (!$clean) $buffer.=$data[$i];
		}
		else if ($time>$oldtime) $buffer.=$data[$i];
	}
  $fh=fopen($filename,'w');
	if ($fh) {
	  flock($fh,LOCK_EX);
		fputs($fh,$buffer);
		fclose($fh);
	}
	return $result;
}

/** Удаление кода и хеша запроса из файла **/
function captcha_clean() {
	$filename='files/captcha2.txt';
  if (!file_exists($filename)) return false;	
  $data=file($filename);
	if (!is_array($data) || count($data)==0) return false; // если не удалось прочитать файл или код CAPTCHA пуст, считаем проверку провалившейся сразу
	$oldtime=time()-3*60*60; // будем считать, что CAPTCHA устаревает через 3 часа
	$result=false;
	$buffer='';
	if (count($data)>10000) $data=array_slice(10000); // если кодов набралось слишком много, просматриваем и сохраняем последние 10000 (защита от DDoS-атаки) 
	for ($i=0, $count=count($data); $i<$count; $i++) {
		list($code,$time,$hash)=explode($data[$i]);
		if ($code!=$_REQUEST['captcha_code'] && $time>$oldtime) $buffer.=$data[$i];
	}
  $fh=fopen($filename,'w');
	if ($fh) {
	  flock($fh,LOCK_EX);
		fputs($fh,$buffer);
		fclose($fh);
	}
}
